package org.snaker.engine.parser.logicflow.model;

import lombok.Data;
import org.apache.commons.collections.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Data
public class LogicFlowData {
    /**
     * 名称
     */
    private String name;
    /**
     * 显示名称
     */
    private String displayName;
    /**
     * 启动流程时，流程实例的流水号生成类
     */
    private String instanceNoClass;
    /**
     * 启动实例URL
     * TODO 考虑是否使用
     */
    private String instanceUrl;
    /**
     * 所有的节点数据
     */
    private List<Node> nodes;
    /**
     * 所有节点之间的连线
     */
    private List<Line> edges;

    private String preInterceptors; // 节点前置拦截器
    private String postInterceptors; // 节点后置拦截器

    @Data
    public static class Node {
        private String id;
        /**
         * snaker:custom 自定义任务
         * snaker:task   用户任务
         * snaker:decision 条件判断
         * snaker:start 开始节点
         * snaker:end 结束节点
         * snaker:transition 连线节点
         * snaker:fork  分支
         * snaker:join   合并
         * snaker:subProcess 子流程
         */
        private String type;
        private int x;
        private int y;
        /**
         * 文字信息
         */
        private Text text;
        /**
         * 业务数据
         */
        private Properties properties;
        /**
         * 子流程ID
         */
        private List<String> children;

        public String getLayout() {
            return String.format("%d,%d,%d,%d", x, y, properties.get("width", Integer.class), properties.get("height", Integer.class));
        }
    }


    @Data
    public static class Text {
        private String value;
        private int x;
        private int y;
    }

    /**
     * 流程图连线
     */
    @Data
    public static class Line {
        private String id;
        /**
         * 起始节点
         */
        private String sourceNodeId;
        /**
         * 解释节点
         */
        private String targetNodeId;
        /**
         * 节点类型
         */
        private String type;
        /**
         * 起始坐标
         */
        private Point startPoint;
        /**
         * 结束坐标
         */
        private Point endPoint;
        /**
         * 坐标连线(顺序), 第一个元素为起始坐标,最后一个元素为结束坐标
         */
        private List<Point> pointsList;
        /**
         * 连线上的文字信息
         */
        private Text text;
        /**
         * 节点携带的业务数据
         */
        private Properties properties;

        public String getG() {

            if (Objects.nonNull(this.getStartPoint()) && Objects.nonNull(this.getEndPoint())) {
                int startPointX = this.getStartPoint().getX();
                int startPointY = this.getStartPoint().getY();
                int endPointX = this.getEndPoint().getX();
                int endPointY = this.getEndPoint().getY();
                return String.format("%d,%d;%d,%d", startPointX, startPointY, endPointX, endPointY);
            }
            if (CollectionUtils.isNotEmpty(this.getPointsList())) {
                return this.getPointsList().stream().map(point -> point.getX() + "," + point.getY()).collect(Collectors.joining(";"));
            }

            return null;
        }
    }

    /**
     * 坐标
     */
    @Data
    public static class Point {
        /**
         * x 坐标
         */
        private int x;
        /**
         * y 坐标
         */
        private int y;
    }

    /**
     * 拓展属性
     */
    public static class Properties extends HashMap<String, Object> {

        public <T> T get(String key, Class<T> type) {
            Object val = super.get(key);
            if (Objects.nonNull(val)) {

                if (type.isAssignableFrom(Integer.class)) {
                    if (val instanceof Integer) {
                        return type.cast(val);
                    }
                    if(val instanceof String) {
                        return type.cast(Integer.parseInt((String)val));
                    }
                }

                if(type.isAssignableFrom(String.class)) {
                    return type.cast(val);
                }

            }
            return null;
        }

        public String get(String key) {
            return get(key, String.class);
        }

        public Properties getProperties(String key) {
            return get(key, Properties.class);
        }
    }
}
